/*
 *    This file is part of CeluMap.
 *
 *    CeluMap is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    CeluMap is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Copyright 2006, 2007, 2008 Gonzalo Merayo
 *    gonzalo (at) celumap.com.ar
 *    www.celumap.com.ar
 *
 */

package geometry;

public class Matrix {
	//private long[][] data = new long[3][3];
	private long data00 =0;
	private long data01 =0;
	private long data02 =0;
	private long data10 =0;
	private long data11 =0;
	private long data12 =0;
	private long data20 =0;
	private long data21 =0;
	private long data22 =0;
	public final static int nshift = 14;
	public final static int pfshift = 1<<nshift;
	public Matrix()
	{
	}
	
	public Matrix(Matrix m){
		data00 = m.data00;
		data01 = m.data01;
		data02 = m.data02;
		data10 = m.data10;
		data11 = m.data11;
		data12 = m.data12;
		data20 = m.data20;
		data21 = m.data21;
		data22 = m.data22;
	}
	public Matrix mul(Matrix m){
		Matrix r =new Matrix();
		r.data00=(data00*m.data00+data01*m.data10+data02*m.data20)>>nshift;
		r.data01=(data00*m.data01+data01*m.data11+data02*m.data21)>>nshift;
		r.data02=(data00*m.data02+data01*m.data12+data02*m.data22)>>nshift;
		r.data10=(data10*m.data00+data11*m.data10+data12*m.data20)>>nshift;
		r.data11=(data10*m.data01+data11*m.data11+data12*m.data21)>>nshift;
		r.data12=(data10*m.data02+data11*m.data12+data12*m.data22)>>nshift;
		r.data20=(data20*m.data00+data21*m.data10+data22*m.data20)>>nshift;
		r.data21=(data20*m.data01+data21*m.data11+data22*m.data21)>>nshift;
		r.data22=(data20*m.data02+data21*m.data12+data22*m.data22)>>nshift;
		return r;
	}
	
	public void mul(Point p, Point r){
		r.x =mulx(p.x,p.y);
		r.y =muly(p.x,p.y);
	}
	public void setIdentity()
	{
		setScale(pfshift);
	}
	public void setTranslate(long x, long y)
	{
		setIdentity();
		data02=x;
		data12=y;
	}
	public void setScale(long d)
	{
		data00 = d;
		data01 = 0;
		data02 = 0;
		data10 = 0;
		data11 = d;
		data12 = 0;
		data20 = 0;
		data21 = 0;
		data22 = d;
	}
	public void getInverse(Matrix dest)
	{
		Inverse(this, dest);
	}
	public void invert()
	{
		Inverse(new Matrix(this), this);
	}
	public static void Inverse(Matrix orig, Matrix dest)
	{
		dest.setIdentity();
		//Normalizo la diagonal de this
		dest.data00<<=nshift;
		dest.data00/=orig.data00;
		dest.data11<<=nshift;
		dest.data11/=orig.data11;
		dest.data22<<=nshift;
		dest.data22/=orig.data22;
		//pongo en 0 lo que queda de this
		dest.data01=- (orig.data01*dest.data00)>>nshift;
		dest.data02=- (orig.data02*dest.data00)>>nshift;
		dest.data10=- (orig.data10*dest.data11)>>nshift;
		dest.data12=- (orig.data12*dest.data11)>>nshift;
		dest.data21=- (orig.data21*dest.data22)>>nshift;
		dest.data22=- (orig.data22*dest.data22)>>nshift;
	}
	public String toString(){
		StringBuffer s = new StringBuffer("[\n");
		s.append("["+data00+","+data01+","+data02+"]\n");
		s.append("["+data10+","+data11+","+data12+"]\n");
		s.append("["+data20+","+data21+","+data22+"]\n");
		s.append("]\n");
		return new String(s);
	}
	
	public final int mulx(int x, int y){
		return (int) ((data00*x+data01*y+data02)>>nshift);
	}
	public final int muly(int x, int y){
		return (int) ((data10*x+data11*y+data12)>>nshift); 
	}
/*	public void rotate90cw() {
		for(int i=0;i<3;i++){
			long tmp = data[i][0];
			data[i][0] = -data[i][1];
			data[i][1] = tmp;
		}
	}
	public void rotate90ccw() {
		for(int i=0;i<3;i++){
			long tmp = data[i][0];
			data[i][0] = data[i][1];
			data[i][1] = -tmp;
		}		
	}
	*/
}
